﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EdytorWF.Objects;
using EdytorWF.Engine;
using System.Windows.Forms;
using Microsoft.DirectX;
using System.Drawing;
using Microsoft.DirectX.Direct3D;
using System.IO;

namespace EdytorWF
{
    public struct ColllisionParams
    {
        public int w_min;
        public int w_max;
        public int h_min;
        public int h_max;

        public ColllisionParams(int _wMin, int _wMax, int _hMin, int _hMax)
        {
            w_min = _wMin;
            w_max = _wMax;
            h_min = _hMin;
            h_max = _hMax;
        }
    };

    enum ECreateObjectModes
    {
        COLLISION = 0,
        CAMERA = 1,
    };

    class IEngine
    {
        private Renderer MainRenderer;

        private static IEngine I_Engine;
        public String DefaultSoundMeshName = "..\\..\\Resources\\Meshes\\sphere_new.msh";
        public String DefaultObjectMeshName = "..\\..\\Resources\\Meshes\\box.msh";
        public String DefaultLightMeshName = "..\\..\\Resources\\Meshes\\piramid.msh";
        public String DefaultSoundTextureName = "..\\..\\Resources\\Textures\\default_sound.png";
        public String DefaultLightTextureName = "..\\..\\Resources\\Textures\\default.png";
        public String DefaultObjectTextureName = "..\\..\\Resources\\Textures\\default_object.png";
        public String DefaultSound = "..\\..\\Resources\\Sounds\\default.wav";

        public Vector3 SelectedPointOnTerrain;
        public ECreateObjectModes CreateObjectMode;

        private IEngine()
        {
            MainRenderer = new Renderer();
            SelectedPointOnTerrain = new Vector3();
            CreateObjectMode = ECreateObjectModes.COLLISION;
        }

        //////////////////////////////////////////////////////////////////////////
        public static IEngine EngineInstance
        {
            get
            {
                if (I_Engine == null)
                {
                    I_Engine = new IEngine();
                }
                return I_Engine;
            }
        }

        //////////////////////////////////////////////////////////////////////////
        bool GetIntersection(float fDist1, float fDist2, Vector3 P1, Vector3 P2, out Vector3 Hit)
        {
            Hit = new Vector3();
            if ((fDist1 * fDist2) >= 0.0f)
                return false;
            if (fDist1 == fDist2)
                return false;
            Hit = P1 + (P2 - P1) * (-fDist1 / (fDist2 - fDist1));

            return true;
        }

        //////////////////////////////////////////////////////////////////////////
        bool InBoundingBox(Vector3 Hit, Vector3 B1, Vector3 B2, int Axis)
        {
            if (Axis == 1)
            {
                if (Hit.Z > B1.Z && Hit.Z < B2.Z && Hit.Y > B1.Y && Hit.Y < B2.Y)
                    return true;
            }
            if (Axis == 2)
            {
                if (Hit.Z > B1.Z && Hit.Z < B2.Z && Hit.Z > B1.Z && Hit.Z < B2.Z)
                    return true;
            }
            if (Axis == 3)
            {
                if (Hit.X > B1.X && Hit.X < B2.X && Hit.Y > B1.Y && Hit.Y < B2.Y)
                    return true;
            }

            return false;
        }

        //////////////////////////////////////////////////////////////////////////
        bool CheckLineBox(Vector3 B1, Vector3 B2, Vector3 L1, Vector3 L2, out Vector3 Hit)
        {
            Hit = new Vector3(0, 0, 0);
            if (L2.X < B1.X && L1.X < B1.X)
                return false;
            if (L2.X > B2.X && L1.X > B2.X)
                return false;
            if (L2.Y < B1.Y && L1.Y < B1.Y)
                return false;
            if (L2.Y > B2.Y && L1.Y > B2.Y)
                return false;
            if (L2.Z < B1.Z && L1.Z < B1.Z)
                return false;
            if (L2.Z > B2.Z && L1.Z > B2.Z)
                return false;

            if (L1.X > B1.X && L1.X < B2.X &&
                L1.Y > B1.Y && L1.Y < B2.Y &&
                L1.Z > B1.Z && L1.Z < B2.Z)
            {
                Hit = L1;
                return true;
            }

            if ((GetIntersection(L1.X - B1.X, L2.X - B1.X, L1, L2, out Hit) && InBoundingBox(Hit, B1, B2, 1))
              || (GetIntersection(L1.Y - B1.Y, L2.Y - B1.Y, L1, L2, out Hit) && InBoundingBox(Hit, B1, B2, 2))
              || (GetIntersection(L1.Z - B1.Z, L2.Z - B1.Z, L1, L2, out Hit) && InBoundingBox(Hit, B1, B2, 3))
              || (GetIntersection(L1.X - B2.X, L2.X - B2.X, L1, L2, out Hit) && InBoundingBox(Hit, B1, B2, 1))
              || (GetIntersection(L1.Y - B2.Y, L2.Y - B2.Y, L1, L2, out Hit) && InBoundingBox(Hit, B1, B2, 2))
              || (GetIntersection(L1.Z - B2.Z, L2.Z - B2.Z, L1, L2, out Hit) && InBoundingBox(Hit, B1, B2, 3)))
                return true;

            return false;
        }

        //////////////////////////////////////////////////////////////////////////
        public IObject FindObjectByCollision(Point mouse_click)
        {
            float width, height;
            MainRenderer.GetControlSize(out width, out height);

            float camera_point_x = width / 2;
            float camera_point_y = height / 2;

            float del_x = mouse_click.X - camera_point_x;
            float del_y = mouse_click.Y - camera_point_y;

            Vector3 forward = MainRenderer.ViewCamera.GetForwardRotate(del_x * (-0.1f), del_y * (-0.1f), 0);

            foreach (IObject s in MainRenderer.ObjectList)
            {
                if (s.CollisionBox == null)
                    continue;

                Vector3 Hit;
                Vector3 pos = MainRenderer.ViewCamera.Position;
                Vector3 pos2 = MainRenderer.ViewCamera.Position + forward * MainRenderer.ViewCamera.ZFar;
                bool res = CheckLineBox(s.CollisionBox.B1, s.CollisionBox.B2, pos, pos2, out Hit);
                if (res)
                {
                    return s;
                }
            }
            return null;
        }

        //////////////////////////////////////////////////////////////////////////
        public IObject FindObjectByCollisionNew(Point mouse_click)
        {
            float width, height;
            MainRenderer.GetControlSize(out width, out height);

            float camera_point_x = width / 2;
            float camera_point_y = height / 2;

            float del_x = mouse_click.X - camera_point_x;
            float del_y = mouse_click.Y - camera_point_y;

            Vector3 forward = MainRenderer.ViewCamera.GetForwardRotate(del_x * (-0.1f), del_y * (-0.1f), 0);

            foreach (IObject s in MainRenderer.ObjectList)
            {
                if (s.CollisionBox == null)
                    continue;

                Vector3 pos = MainRenderer.ViewCamera.Position;
                Vector3 pos2 = MainRenderer.ViewCamera.Position + forward * MainRenderer.ViewCamera.ZFar;
                bool res = IsCollisionByBox(pos, pos2, s.CollisionBox);
                if (res)
                {
                    return s;
                }
            }
            return null;
        }

        //////////////////////////////////////////////////////////////////////////
        public bool FindCollisionOnTerrain(Point mouse_click)
        {
            float width, height;
            MainRenderer.GetControlSize(out width, out height);

            float camera_point_x = width / 2;
            float camera_point_y = height / 2;

            float del_x = mouse_click.X - camera_point_x;
            float del_y = mouse_click.Y - camera_point_y;

            Vector3 forward = MainRenderer.ViewCamera.GetForwardRotate(del_x * (-0.1f), del_y * (-0.1f), 0);

            Vector3 pos = MainRenderer.ViewCamera.Position;
            Vector3 pos2 = MainRenderer.ViewCamera.Position + forward * MainRenderer.ViewCamera.ZFar;

            return FindCollision(pos, pos2);
        }

        //////////////////////////////////////////////////////////////////////////
        public bool FindTerrainCollision()
        {
            Vector3 pos = MainRenderer.ViewCamera.Position;
            Vector3 pos2 = new Vector3(pos.X, -100, pos.Z);

            return FindCollision(pos, pos2);
        }
        //////////////////////////////////////////////////////////////////////////
        public bool FindCollision(Vector3 pos, Vector3 pos2)
        {
            if (!IsCollisionByBox(pos, pos2, MainRenderer.MyEnvironment.MyTerrain.CollisionBox))
            {
                return false;
            }

            int width = MainRenderer.MyEnvironment.MyTerrain.ResolutionX;
            int height = MainRenderer.MyEnvironment.MyTerrain.ResolutionY;
            ColllisionParams coll_params;
            ColllisionParams init_params = new ColllisionParams(1, width - 1, 1, height - 1);
            bool is_collision = CheckCollisionArea(pos, pos2, width, height, init_params, out coll_params);

            if (!is_collision)
                return false;

            Vector3 tmp;
            bool ret = false;
            for (int i = coll_params.w_min; i <= coll_params.w_max; i++)
                for (int j = coll_params.h_min; j <= coll_params.h_max; j++)
                {
                    int vec_1 = i * height + j - 1;
                    int vec_2 = (i - 1) * height + j - 1;
                    int vec_3 = (i - 1) * height + j;

                    CustomVertex.PositionNormalTextured Pos_1 = MainRenderer.MyEnvironment.MyTerrain.Vertices[vec_1];
                    CustomVertex.PositionNormalTextured Pos_2 = MainRenderer.MyEnvironment.MyTerrain.Vertices[vec_2];
                    CustomVertex.PositionNormalTextured Pos_3 = MainRenderer.MyEnvironment.MyTerrain.Vertices[vec_3];

                    ret = IsCollisionByTriangle(pos, pos2, Pos_1.Position, Pos_2.Position, Pos_3.Position, out tmp);
                    if (ret)
                    {
                        SelectedPointOnTerrain = tmp;
                        //MainRenderer.ViewCamera.Position = new Vector3(SelectedPointOnTerrain.X, SelectedPointOnTerrain.Y + 5, SelectedPointOnTerrain.Z);
                        return true;
                    }

                    int vec_4 = i * height + j;
                    int vec_5 = i * height + j - 1;
                    int vec_6 = (i - 1) * height + j;

                    Pos_1 = MainRenderer.MyEnvironment.MyTerrain.Vertices[vec_4];
                    Pos_2 = MainRenderer.MyEnvironment.MyTerrain.Vertices[vec_5];
                    Pos_3 = MainRenderer.MyEnvironment.MyTerrain.Vertices[vec_6];

                    ret = IsCollisionByTriangle(pos, pos2, Pos_1.Position, Pos_2.Position, Pos_3.Position, out tmp);
                    if (ret)
                    {
                        SelectedPointOnTerrain = tmp;
                        //MainRenderer.ViewCamera.Position = new Vector3(SelectedPointOnTerrain.X, SelectedPointOnTerrain.Y + 5, SelectedPointOnTerrain.Z);
                        return true;
                    }
                }

            return false;
        }
        //////////////////////////////////////////////////////////////////////////
        public bool CheckCollisionArea(Vector3 start_line, Vector3 end_line, int width, int height, ColllisionParams init_params, out ColllisionParams out_params)
        {
            int w = (init_params.w_max - init_params.w_min);
            int h = (init_params.h_max - init_params.h_min);
            int half_width = init_params.w_min + w / 2;
            int half_height = init_params.h_min + h / 2;

            out_params = new ColllisionParams();

            //(i-1)*NoZ + j - 1
            //i * NoZ + j

            int i_min, j_min, i_max, j_max, id1, id2;

            // i : (1 ; NoX/2)
            // j : (1 ; NoZ/2)
            i_min = init_params.w_min;
            j_min = init_params.h_min;
            id1 = (i_min - 1) * height + j_min - 1;
            i_max = half_width;
            j_max = half_height;
            id2 = i_max * height + j_max;

            Vector3 up_left_b1 = MainRenderer.MyEnvironment.MyTerrain.Vertices[id1].Position;
            Vector3 up_left_b2 = MainRenderer.MyEnvironment.MyTerrain.Vertices[id2].Position;
            BoundingBox up_left = new BoundingBox(up_left_b1, up_left_b2);
            if (IsCollisionByBox(start_line, end_line, up_left))
            {
                out_params.w_min = i_min;
                out_params.w_max = i_max;
                out_params.h_min = j_min;
                out_params.h_max = j_max;

                bool r = true;
                ColllisionParams out_p;
                if (w > 25 || h > 25)
                {
                    r = CheckCollisionArea(start_line, end_line, width, height, out_params, out out_p);
                    out_params = out_p;
                }

                return r;
            }
            // i : (NoX/2 + 1 ; NoX-1)
            // j : (1 ; NoZ/2)
            i_min = half_width + 1;
            j_min = init_params.h_min;
            id1 = (i_min - 1) * height + j_min - 1;
            i_max = init_params.w_max;
            j_max = half_height;
            id2 = i_max * height + j_max;

            Vector3 up_right_b1 = MainRenderer.MyEnvironment.MyTerrain.Vertices[id1].Position;
            Vector3 up_right_b2 = MainRenderer.MyEnvironment.MyTerrain.Vertices[id2].Position;
            BoundingBox up_right = new BoundingBox(up_right_b1, up_right_b2);
            if (IsCollisionByBox(start_line, end_line, up_right))
            {
                out_params.w_min = i_min;
                out_params.w_max = i_max;
                out_params.h_min = j_min;
                out_params.h_max = j_max;

                bool r = true;
                ColllisionParams out_p;
                if (w > 25 || h > 25)
                {
                    r = CheckCollisionArea(start_line, end_line, width, height, out_params, out out_p);
                    out_params = out_p;
                }

                return r;
            }

            // i : (1 ; NoX/2)
            // j : (NoZ/2 + 1; NoZ - 1)
            i_min = init_params.w_min;
            j_min = half_height + 1;
            id1 = (i_min - 1) * height + j_min - 1;
            i_max = half_width;
            j_max = init_params.h_max;
            id2 = i_max * height + j_max;

            Vector3 down_left_b1 = MainRenderer.MyEnvironment.MyTerrain.Vertices[id1].Position;
            Vector3 down_left_b2 = MainRenderer.MyEnvironment.MyTerrain.Vertices[id2].Position;
            BoundingBox down_left = new BoundingBox(down_left_b1, down_left_b2);
            if (IsCollisionByBox(start_line, end_line, down_left))
            {
                out_params.w_min = i_min;
                out_params.w_max = i_max;
                out_params.h_min = j_min;
                out_params.h_max = j_max;

                bool r = true;
                ColllisionParams out_p;
                if (w > 25 || h > 25)
                {
                    r = CheckCollisionArea(start_line, end_line, width, height, out_params, out out_p);
                    out_params = out_p;
                }

                return r;
            }

            // i : (NoX/2 + 1; Nox - 1)
            // j : (NoZ/2 + 1; NoZ - 1)
            i_min = half_width + 1;
            j_min = half_height + 1;
            id1 = (i_min - 1) * height + j_min - 1;
            i_max = init_params.w_max;
            j_max = init_params.h_max;
            id2 = i_max * height + j_max;

            Vector3 down_right_b1 = MainRenderer.MyEnvironment.MyTerrain.Vertices[id1].Position;
            Vector3 down_right_b2 = MainRenderer.MyEnvironment.MyTerrain.Vertices[id2].Position;
            BoundingBox down_right = new BoundingBox(down_right_b1, down_right_b2);
            if (IsCollisionByBox(start_line, end_line, down_right))
            {
                out_params.w_min = i_min;
                out_params.w_max = i_max;
                out_params.h_min = j_min;
                out_params.h_max = j_max;
                bool r = true;
                ColllisionParams out_p;
                if (w > 25 || h > 25)
                {
                    r = CheckCollisionArea(start_line, end_line, width, height, out_params, out out_p);
                    out_params = out_p;
                }

                return r;
            }

            return false;
        }
        //////////////////////////////////////////////////////////////////////////
        public void TrackCollision(Point mouse_click)
        {
            float width, height;
            MainRenderer.GetControlSize(out width, out height);

            float camera_point_x = width / 2;
            float camera_point_y = height / 2;

            float del_x = mouse_click.X - camera_point_x;
            float del_y = mouse_click.Y - camera_point_y;

            Vector3 forward = MainRenderer.ViewCamera.GetForwardRotate(del_x * (-0.1f), del_y * (-0.1f), 0);
            Vector3 far = MainRenderer.ViewCamera.Position + forward * MainRenderer.ViewCamera.ZFar;
            MainRenderer.SetCollisionHelper(far);
            MainRenderer.Render();
        }

        //////////////////////////////////////////////////////////////////////////
        public bool IsCollisionByBox(Vector3 start_line, Vector3 end_line, BoundingBox box)
        {
            bool ret = false;

            ret = IsCollisionByRect(start_line, end_line, new Vector3(box.B1.X, box.B2.Y, box.B1.Z),
                new Vector3(box.B2.X, box.B2.Y, box.B1.Z), new Vector3(box.B1.X, box.B1.Y, box.B1.Z), new Vector3(box.B2.X, box.B1.Y, box.B1.Z));
            if (ret)
                return ret;

            ret = IsCollisionByRect(start_line, end_line, new Vector3(box.B1.X, box.B2.Y, box.B2.Z),
                new Vector3(box.B1.X, box.B2.Y, box.B1.Z), new Vector3(box.B1.X, box.B1.Y, box.B2.Z), new Vector3(box.B1.X, box.B1.Y, box.B1.Z));
            if (ret)
                return ret;

            ret = IsCollisionByRect(start_line, end_line, new Vector3(box.B2.X, box.B2.Y, box.B1.Z),
                new Vector3(box.B2.X, box.B2.Y, box.B2.Z), new Vector3(box.B2.X, box.B1.Y, box.B1.Z), new Vector3(box.B2.X, box.B1.Y, box.B2.Z));
            if (ret)
                return ret;

            ret = IsCollisionByRect(start_line, end_line, new Vector3(box.B2.X, box.B2.Y, box.B2.Z),
                new Vector3(box.B1.X, box.B2.Y, box.B2.Z), new Vector3(box.B2.X, box.B1.Y, box.B2.Z), new Vector3(box.B1.X, box.B1.Y, box.B2.Z));
            if (ret)
                return ret;

            ret = IsCollisionByRect(start_line, end_line, new Vector3(box.B1.X, box.B2.Y, box.B2.Z),
                new Vector3(box.B2.X, box.B2.Y, box.B2.Z), new Vector3(box.B1.X, box.B2.Y, box.B1.Z), new Vector3(box.B2.X, box.B2.Y, box.B1.Z));
            if (ret)
                return ret;

            ret = IsCollisionByRect(start_line, end_line, new Vector3(box.B1.X, box.B1.Y, box.B2.Z),
                new Vector3(box.B2.X, box.B1.Y, box.B2.Z), new Vector3(box.B1.X, box.B1.Y, box.B1.Z), new Vector3(box.B2.X, box.B1.Y, box.B1.Z));
            if (ret)
                return ret;

            return ret;
        }

        //////////////////////////////////////////////////////////////////////////
        public bool IsCollisionByRect(Vector3 start_line, Vector3 end_line, Vector3 up_left, Vector3 up_right, Vector3 down_left, Vector3 down_right)
        {
            bool ret = false;

            Vector3 Hit;
            ret = IsCollisionByTriangle(start_line, end_line, up_left, up_right, down_right, out Hit);
            if (ret)
                return ret;

            ret = IsCollisionByTriangle(start_line, end_line, up_left, down_right, down_left, out Hit);
            if (ret)
                return ret;

            return ret;
        }
        //////////////////////////////////////////////////////////////////////////
        public bool IsCollisionByTriangle(Vector3 start_line, Vector3 end_line, Vector3 point_1, Vector3 point_2, Vector3 point_3, out Vector3 result)
        {
            bool ret = false;
            result = new Vector3();

            Vector3 P1P2 = point_2 - point_1; // P1P2 = P2 - P1
            Vector3 P1P3 = point_3 - point_1; // P1P3 = P3 - P1

            Vector3 l1l2 = end_line - start_line; //l1l2 = l2 - l1

            Vector3 n = Vector3.Cross(P1P2, P1P3); // n = P1P2 x P1P3
            float val_x = -point_1.X * n.X;
            float val_y = -point_1.Y * n.Y;
            float val_z = -point_1.Z * n.Z;

            float val = val_x + val_y + val_z; // D
            //P : (vec - P1) * n  = 0
            //P : (x - P1.x, y - P1.y, z - P1.z)o(n.X, n.Y, n.Z) = 0
            //P : Ax + By + Cz + D = 0

            //l: l1 + t*l1l2
            //P: A(l1.x + t*l1l2.x) + B(l1.Y + t*l1l2.Y) + C(l1.Z + t*l1l2.Z) + D = 0

            float res_t_x = n.X * l1l2.X; // A*l1l2.x
            float res_t_y = n.Y * l1l2.Y; // B*l1l2.y
            float res_t_z = n.Z * l1l2.Z; // C*l1l2.z

            float res_x = n.X * start_line.X; //A*l1.x
            float res_y = n.Y * start_line.Y; //B*l1.y
            float res_z = n.Z * start_line.Z; //C*l1.z

            // P: A*l1.x + A*t*l1l2.x + B*l1.Y + B*t*l1l2.Y + C*l1.Z + C*t*l1l2.Z + D = 0
            // P: A*t*l1l2.x + B*t*l1l2.Y + C*t*l1l2.Z = -D - A*l1.x - B*l1.Y - C*l1.Z

            float res = -val - res_x - res_y - res_z; //-D - A*l1.x - B*l1.Y - C*l1.Z
            float res_t = res_t_x + res_t_y + res_t_z; //A*t*l1l2.x + B*t*l1l2.Y + C*t*l1l2.Z

            //t(A*l1l2.x + B*l1l2.Y + C*l1l2.Z) = -D - A*l1.x - B*l1.Y - C*l1.Z
            //t = -D - A*l1.x - B*l1.Y - C*l1.Z/(A*l1l2.x + B*l1l2.Y + C*l1l2.Z)
            if (res_t == 0)
                return false;

            float wynik = res / res_t;

            float line_x = start_line.X + wynik * l1l2.X; //A(l1.x + t*l1l2.x)
            float line_y = start_line.Y + wynik * l1l2.Y; //B(l1.Y + t*l1l2.Y)
            float line_z = start_line.Z + wynik * l1l2.Z; //C(l1.Z + t*l1l2.Z)

            Vector3 Res_Point = result = new Vector3(line_x, line_y, line_z);

            //Vector3 PrP1 = point_1 - Res_Point;
            //Vector3 PrP2 = point_2 - Res_Point;
            //Vector3 PrP3 = point_3 - Res_Point;

            //float PrP1_n = PrP1.Length(); // |PrP1|
            //float PrP2_n = PrP2.Length(); // |PrP2|
            //float PrP3_n = PrP3.Length(); // |PrP3|

            //float val_P1P2 = Vector3.Dot(PrP1, PrP2) / (PrP1_n * PrP2_n);
            //float kat_PrP1P2 = (float)Math.Acos(val_P1P2); // arccos(PrP1 o PrP2/|PrP1|*|PrP2|)
            //float val_P1P3 = Vector3.Dot(PrP1, PrP3) / (PrP1_n * PrP3_n);
            //float kat_PrP1P3 = (float)Math.Acos(val_P1P3); // arccos(PrP1 o PrP3/|PrP1|*|PrP3|)
            //float val_PrP2P3 = Vector3.Dot(PrP2, PrP3) / (PrP2_n * PrP3_n);
            //float kat_PrP2P3 = (float)Math.Acos(val_PrP2P3); // arccos(PrP2 o PrP3/|PrP2|*|PrP3|)

            //float sum = (kat_PrP1P2 + kat_PrP1P3 + kat_PrP2P3);
            //float rad = 2.0f * (float)Math.PI;
            //float comparer = rad - 0.0001f;
            //if (sum >= comparer && sum <= (rad + 0.0001))
            //{
            //    ret = true;
            //    result = Res_Point;
            //}
            //return ret;

            ////----------------------------------


            float p1 = Vector3.Cross(point_1 - Res_Point, point_2 - Res_Point).Length();
            float p2 = Vector3.Cross(point_1 - Res_Point, point_3 - Res_Point).Length();
            float p3 = Vector3.Cross(point_2 - Res_Point, point_3 - Res_Point).Length();
            float p = Vector3.Cross(point_3 - point_1, point_2 - point_1).Length();

            return p1 + p2 + p3 - 10 < p;

        }

        //////////////////////////////////////////////////////////////////////////
        public void UpdateCamera()
        {
            if (MainRenderer != null)
            {
                MainRenderer.UpdateCamera();
                MainRenderer.Render();
            }
        }

        //////////////////////////////////////////////////////////////////////////
        public void UpdateLights()
        {
            if (MainRenderer != null)
            {
                MainRenderer.UpdateLights();
                MainRenderer.Render();
            }
        }
        //////////////////////////////////////////////////////////////////////////
        public void Refresh()
        {
            UpdateCamera();
            UpdateLights();
        }
        //////////////////////////////////////////////////////////////////////////
        public void MoveCamera(float x, float y, float z)
        {
            MainRenderer.ViewCamera.Move(x, y, z);
            MainRenderer.UpdateCamera();
        }

        //////////////////////////////////////////////////////////////////////////
        public void MovePersonCamera(Vector3 new_position)
        {
            Vector3 pos = new Vector3(new_position.X, new_position.Y + 5, new_position.Z);
            MainRenderer.ViewCamera.Position = pos;

            MainRenderer.UpdateCamera();
        }

        //////////////////////////////////////////////////////////////////////////
        public void RotateCamera(float p, float y, float r)
        {
            MainRenderer.ViewCamera.Rotate(p, y, r);
            MainRenderer.UpdateCamera();
        }

        //////////////////////////////////////////////////////////////////////////
        public void MoveSun(float da, float db, float dr)
        {
            MainRenderer.MoveSun(da, db, dr);
        }

        //////////////////////////////////////////////////////////////////////////
        public void SetWireFrame()
        {
            MainRenderer.SetWireFrame();
        }

        //////////////////////////////////////////////////////////////////////////
        public void SetSolid()
        {
            MainRenderer.SetSolid();
        }

        //////////////////////////////////////////////////////////////////////////
        public void SetView(Control control, ref Camera camera)
        {
            MainRenderer.Initialize(control, ref camera);
        }

        //////////////////////////////////////////////////////////////////////////
        /*public void CreateTerrain()
        {
            Terrain MyTerrain = new Terrain(MainRenderer.MyDevice);
            MainRenderer.AddTerrain(MyTerrain);
        }*/

        //////////////////////////////////////////////////////////////////////////
        public List<IObject> GetObjectList()
        {
            return MainRenderer.ObjectList;
        }

        //////////////////////////////////////////////////////////////////////////
        public void RemoveObject(IObject sel_obj)
        {
            if (sel_obj.GetTypeName() == "_LIGHT_OBJECT")
            {
                MainRenderer.LigthList.Remove((LightObject)sel_obj);
                MainRenderer.UpdateLights();
            }
            else if (sel_obj.GetTypeName() == "_SOUND_OBJECT")
            {
                MainRenderer.SoundList.Remove(((SoundObject)sel_obj).GetListener());
            }
            MainRenderer.ObjectList.Remove(sel_obj);
            MainRenderer.Render();
        }

        //////////////////////////////////////////////////////////////////////////
        public ViewInfo CreateViewInfo()
        {
            ViewInfo info = new ViewInfo(MainRenderer.MyDevice);
            MainRenderer.AddViewInfo(ref info);
            MainRenderer.Render();
            return info;
        }

        //////////////////////////////////////////////////////////////////////////
        public bool CreateParticleObject()
        {
            bool ret = false;
            if (CreateObjectMode == ECreateObjectModes.COLLISION)
            {
                ret = MainRenderer.CreateParticleObject(SelectedPointOnTerrain);
            }
            else if (CreateObjectMode == ECreateObjectModes.CAMERA)
            {
                ret = MainRenderer.CreateParticleObject(MainRenderer.ViewCamera.Position);
            }
            MainRenderer.Render();
            return ret;
        }

        //////////////////////////////////////////////////////////////////////////
        public bool CreateModelObject()
        {
            bool ret = false;
            if (CreateObjectMode == ECreateObjectModes.COLLISION)
            {
                ret = MainRenderer.CreateModelObject(SelectedPointOnTerrain);
            }
            else if (CreateObjectMode == ECreateObjectModes.CAMERA)
            {
                ret = MainRenderer.CreateModelObject(MainRenderer.ViewCamera.Position);
            }
            MainRenderer.Render();
            return ret;
        }

        //////////////////////////////////////////////////////////////////////////
        public void SetCreateObjectMode(ECreateObjectModes mode)
        {
            CreateObjectMode = mode;
        }

        //////////////////////////////////////////////////////////////////////////
        public bool CreateSoundObject()
        {
            bool ret = false;
            if (CreateObjectMode == ECreateObjectModes.COLLISION)
            {
                ret = MainRenderer.CreateSoundObject(SelectedPointOnTerrain);
            }
            else if (CreateObjectMode == ECreateObjectModes.CAMERA)
            {
                ret = MainRenderer.CreateSoundObject(MainRenderer.ViewCamera.Position);
            }
            MainRenderer.Render();
            return ret;
        }

        /////////////////////////////////////////////////////////////////////////
        public bool CreateLightObject()
        {
            bool ret = false;
            if (CreateObjectMode == ECreateObjectModes.COLLISION)
            {
                ret = MainRenderer.CreateLightObject(SelectedPointOnTerrain);
            }
            else if (CreateObjectMode == ECreateObjectModes.CAMERA)
            {
                ret = MainRenderer.CreateLightObject(MainRenderer.ViewCamera.Position);
            }
            MainRenderer.Render();
            return ret;
        }

        //////////////////////////////////////////////////////////////////////////
        public void LoadMeshFromFile(String FileName, out List<CustomVertex.PositionNormalTextured> Vertices, out List<int> Indices)
        {
            Vertices = new List<CustomVertex.PositionNormalTextured>();
            List<float> normals = new List<float>();
            List<float> textures = new List<float>();

            Indices = new List<int>();

            StreamReader read_file = new StreamReader(FileName);
            bool was_indices = false;
            do
            {
                String tmp = read_file.ReadLine();
                if (tmp.Contains("Indices"))
                    was_indices = true;

                else if (!was_indices)
                {
                    string[] vec = tmp.Split(';');
                    if (vec.Length == 5)
                    {
                        CustomVertex.PositionNormalTextured vertex = new CustomVertex.PositionNormalTextured();
                        vertex.X = float.Parse(vec[0]);
                        vertex.Y = float.Parse(vec[1]);
                        vertex.Z = float.Parse(vec[2]);

                        vertex.Tu = float.Parse(vec[3]);
                        vertex.Tv = float.Parse(vec[4]);
                        Vertices.Add(vertex);
                    }
                }
                else
                {
                    string[] vec = tmp.Split(';');
                    if (vec.Length == 3)
                    {
                        Indices.Add(int.Parse(vec[0]));
                        Indices.Add(int.Parse(vec[1]));
                        Indices.Add(int.Parse(vec[2]));
                    }
                }

            } while (!read_file.EndOfStream);

            read_file.Close();
        }
        //////////////////////////////////////////////////////////////////////////////////////////////////////////
        public void CreateMesh(String SaveFile, Vector3 Position)
        {
            int Steps = 50;
            int Radius = 5;

            List<CustomVertex.PositionNormalTextured> vertices = new List<CustomVertex.PositionNormalTextured>();
            List<int> indices = new List<int>();

            StreamWriter fileStream = new StreamWriter(SaveFile);
            fileStream.WriteLine("Vertices");
            fileStream.WriteLine("{");

            for (int i = 0; i < Steps; i++)
            {
                float teta = ((float)i / Steps) * 2 * (float)Math.PI;

                for (int j = 0; j < Steps; j++)
                {
                    float phi = ((float)j / Steps) * 2 * (float)Math.PI;

                    float new_X = Position.X + (float)Radius * (float)Math.Sin(teta) * (float)Math.Cos(phi);
                    float new_Y = Position.Y + (float)Radius * (float)Math.Cos(teta);
                    float new_Z = Position.Z + (float)Radius * (float)Math.Sin(teta) * (float)Math.Sin(phi);

                    vertices.Add(new CustomVertex.PositionNormalTextured
                    {
                        X = new_X,
                        Y = new_Y,
                        Z = new_Z,

                        Tu = (float)j / Steps,
                        Tv = (float)i / Steps
                    });

                    fileStream.WriteLine(String.Format("{0}; {1}; {2}; {3}; {4}", new_X, new_Y, new_Z, (float)j / Steps, (float)i / Steps));
                    int a = (Steps * i + j) % (Steps * Steps);
                    int b = (Steps * i + j + 1) % (Steps * Steps); // add % Steps 'n' enjoy :P
                    int c = (Steps * (i + 1) + j) % (Steps * Steps);
                    int d = (Steps * (i + 1) + j + 1) % (Steps * Steps); // add % Steps 'n' enjoy :P

                    indices.AddRange(new int[] { b, c, a });
                    indices.AddRange(new int[] { c, b, d });
                }
            }

            fileStream.WriteLine("}");
            fileStream.WriteLine("Indices");
            fileStream.WriteLine("{");
            int indices_count = 0;
            while (indices_count <= indices.Count - 1)
            {
                fileStream.WriteLine("{0}; {1}; {2}", indices[indices_count++], indices[indices_count++], indices[indices_count++]);
            }
            fileStream.WriteLine("}");
            fileStream.Close();
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////
        public void SetTypeView(EViewType type)
        {
            MainRenderer.TypeView = type;
        }
        //////////////////////////////////////////////////////////////////////////
        public bool IsPointInBox(Vector3 point, BoundingBox box)
        {
            if (point.X > box.B1.X && point.Y > box.B1.Y && point.Z > box.B1.Z)
            {
                if (point.X < box.B2.X && point.Y < box.B2.Y && point.Z < box.B2.Z)
                {
                    return true;
                }
            }
            return false;
        }
        //////////////////////////////////////////////////////////////////////////
    }
}
